#include <stdio.h>
#include <stdlib.h>
#include "PartidaMultijugador.h"
#include "../modelo/Escenario.h"
#include "../modelo/Nivel.h"
#include "../common/AdministradorDeNiveles.h"
#include <algorithm>

PartidaMultijugador::PartidaMultijugador(GestorDeCliente* creador, short nivel, short cantidadDeJugadores, short IdPartida)
{	
	this->cantidadDeJugadores = cantidadDeJugadores;
	this->IdPartida = IdPartida;
	juego = new Juego(cantidadDeJugadores);
	this->hookEvent(juego->getEscenario());
	this->hookEvent(juego);
	this->nivel = nivel;
	
	idJugadoresDisponibles = juego->getIdJugadores();
	lugaresLibres = cantidadDeJugadores;
	sinConfirmar = cantidadDeJugadores;
	conectarCliente(creador);
}

PartidaMultijugador::~PartidaMultijugador(void)
{
	delete (juego);
}

bool PartidaMultijugador::conectarCliente(GestorDeCliente* cliente) {
	if (lugaresLibres > 0) {
		mutexConectarCliente.lock();
		clientesConectados.push_back(cliente);
		cliente->setIdEnPartida(idJugadoresDisponibles.top());
		idJugadoresDisponibles.pop();
		lugaresLibres--;
		mutexConectarCliente.unlock();
		
		if (lugaresLibres == 0) {
			for (size_t i = 0; i < clientesConectados.size(); i++) clientesConectados[i]->notificarInicio();
		} else {
			// le avisa a los clientes mediante evento cuantos faltan
		}
		return true;
	}
	return false;
}

void PartidaMultijugador::desconectarCliente(GestorDeCliente* cliente) {
	mutexConectarCliente.lock();
	clientesConectados.erase(remove(clientesConectados.begin(), clientesConectados.end(), cliente), clientesConectados.end());
	//idJugadoresDisponibles.push(cliente->getIdEnPartida());
	//lugaresLibres++;
	mutexConectarCliente.unlock();
}

void PartidaMultijugador::confirmarInicio() {
	mutexConfirmacion.lock();
	sinConfirmar--;
	mutexConfirmacion.unlock();
	if (sinConfirmar == 0){
		ejecutar();
	}
}
void PartidaMultijugador::ejecutar() {
	AdministradorDeNiveles admin;

	juego->cargarNivel(admin.instanciarNivel(this->nivel,cantidadDeJugadores));
	juego->iniciar();
}

short PartidaMultijugador::getId() {
	return IdPartida;
}

short PartidaMultijugador::getLugaresLibres() {
	return lugaresLibres;
}

Juego* PartidaMultijugador::getJuego() {
	return juego;
}

void PartidaMultijugador::handlerNuevo(Objeto *obj) {
	for (size_t i = 0; i < clientesConectados.size(); i++) clientesConectados[i]->notificarObjetoNuevo(obj);
}

void PartidaMultijugador::handlerDestruido(short id) {
	for (size_t i = 0; i < clientesConectados.size(); i++) clientesConectados[i]->notificarObjetoDestruido(id);
}

void PartidaMultijugador::handlerGanada(short nada) {
	for (size_t i = 0; i < clientesConectados.size(); i++) clientesConectados[i]->notificarPartidaGanada();
	clientesConectados[0]->matarPartida();
}

void PartidaMultijugador::handlerPerdida(short nada) {
	for (size_t i = 0; i < clientesConectados.size(); i++) clientesConectados[i]->notificarPartidaPerdida();
	clientesConectados[0]->matarPartida();
}

void PartidaMultijugador::hookEvent(Escenario* pSource) {
	pSource->eventoObjNuevo.connect(sigc::mem_fun(*this, &PartidaMultijugador::handlerNuevo));
	pSource->eventoObjDestruido.connect(sigc::mem_fun(*this, &PartidaMultijugador::handlerDestruido));
}
void PartidaMultijugador::hookEvent(Juego* pSource) {
	pSource->eventoPerdida.connect(sigc::mem_fun(*this, &PartidaMultijugador::handlerPerdida));
	pSource->eventoGanada.connect(sigc::mem_fun(*this, &PartidaMultijugador::handlerGanada));
}

void PartidaMultijugador::unhookEvent(Escenario* pSource) {

}

short PartidaMultijugador::getCodigoNivel() {
	return this->nivel;
}
